// Copyright 2010, The TOFT Authors.
// Author: CHEN Feng <chen3feng@gmail.com>
//
// Copied and modified from Google's Protocol Buffers library.
// google/protobuf/stub/common.h
//
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef TOFT_BASE_SCOPED_PTR_H
#define TOFT_BASE_SCOPED_PTR_H

#include <assert.h>
#include <stddef.h>

// ===================================================================
// from google3/base/scoped_ptr.h

//  This is an implementation designed to match the anticipated future TR2
//  implementation of the scoped_ptr class, and its closely-related brethren,
//  scoped_array, scoped_ptr_malloc, and make_scoped_ptr.

namespace toft {

// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
// automatically deletes the pointer it holds (if any).
// That is, scoped_ptr<T> owns the T object that it points to.
// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
//
// The size of a scoped_ptr is small:
// sizeof(scoped_ptr<C>) == sizeof(C*)
template <class C>
class scoped_ptr {
    // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't
    // make sense, and if C2 == C, it still doesn't make sense because you should
    // never have the same object owned by two different scoped_ptrs.
    template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
    template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;

    // Disallow evil constructors
    scoped_ptr(const scoped_ptr&);
    void operator=(const scoped_ptr&);

    typedef void* SafeBool;

public:
    // The element type
    typedef C element_type;

    // Constructor.  Defaults to intializing with NULL.
    // There is no way to create an uninitialized scoped_ptr.
    // The input parameter must be allocated with new.
    explicit scoped_ptr(C* p = NULL) : ptr_(p) { }

    // Destructor.  If there is a C object, delete it.
    // We don't need to test ptr_ == NULL because C++ does that for us.
    ~scoped_ptr() {
        enum { type_must_be_complete = sizeof(C) };
        delete ptr_;
        ptr_ = reinterpret_cast<C*>(-1);
    }

    // implicit cast to bool
    operator SafeBool() const {
        return ptr_;
    }

    bool operator!() const {
        return ptr_ == 0;
    }

    // Reset.  Deletes the current owned object, if any.
    // Then takes ownership of a new object, if given.
    // this->reset(this->get()) works.
    void reset(C* p = NULL) {
        if (p != ptr_) {
            enum { type_must_be_complete = sizeof(C) };
            delete ptr_;
            ptr_ = p;
        }
    }

    // Accessors to get the owned object.
    // operator* and operator-> will assert() if there is no current object.
    C& operator*() const {
        assert(ptr_ != NULL);
        return *ptr_;
    }
    C* operator->() const  {
        assert(ptr_ != NULL);
        return ptr_;
    }
    C* get() const { return ptr_; }

    // Comparison operators.
    // These return whether two scoped_ptr refer to the same object, not just to
    // two different but equal objects.
    bool operator==(C* p) const { return ptr_ == p; }
    bool operator!=(C* p) const { return ptr_ != p; }

    // Swap two scoped pointers.
    void swap(scoped_ptr& p2) {
        C* tmp = ptr_;
        ptr_ = p2.ptr_;
        p2.ptr_ = tmp;
    }

    // Release a pointer.
    // The return value is the current pointer held by this object.
    // If this object holds a NULL pointer, the return value is NULL.
    // After this operation, this object will hold a NULL pointer,
    // and will not own the object any more.
    C* release() {
        C* retVal = ptr_;
        ptr_ = NULL;
        return retVal;
    }

private:
    C* ptr_;
};

} // namespace toft

#endif // TOFT_BASE_SCOPED_PTR_H_
